"""
SteHub Flask应用工厂模块
"""
import os
import logging
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
from flask_socketio import SocketIO
from flask_cors import CORS
from flask_jwt_extended import JWTManager
from dotenv import load_dotenv

# 扩展对象
db = SQLAlchemy()
migrate = Migrate()
login_manager = LoginManager()
socketio = SocketIO()
jwt = JWTManager()
cors = CORS()

# 导入模型以确保它们被注册
from app.models.user import User
from app.models.forum import Post, Comment, Category
from app.models.chat import ChatRoom, Message, UserChatRoom
from app.models.file import File

# 导入蓝图
from app.routes.main import main_bp
from app.routes.auth import auth_bp
from app.routes.forum import forum_bp
from app.routes.chat import chat_bp
from app.routes.api import api_bp
from app.routes.admin import admin_bp

def create_app(config_class=None):
    """
    应用工厂函数
    
    Args:
        config_class: 配置类
    
    Returns:
        Flask应用实例
    """
    # 加载环境变量
    load_dotenv()
    
    # 创建Flask应用实例
    app = Flask(__name__, 
                template_folder='templates',
                static_folder='static')
    
    # 配置应用
    if config_class:
        app.config.from_object(config_class)
    else:
        app.config.from_object('app.config.Config')
    
    # 确保实例目录存在
    os.makedirs(app.instance_path, exist_ok=True)
    
    # 初始化扩展
    initialize_extensions(app)
    
    # 注册蓝图
    register_blueprints(app)
    
    # 注册错误处理器
    register_error_handlers(app)
    
    # 注册上下文处理器
    register_context_processors(app)
    
    # 注册命令行接口
    register_commands(app)
    
    # 配置日志
    configure_logging(app)
    
    return app

def initialize_extensions(app):
    """初始化所有扩展"""
    db.init_app(app)
    migrate.init_app(app, db)
    login_manager.init_app(app)
    socketio.init_app(app, 
                     cors_allowed_origins="*",
                     async_mode='eventlet')
    jwt.init_app(app)
    cors.init_app(app)
    
    # 配置登录管理器
    login_manager.login_view = 'auth.login'
    login_manager.login_message = '请先登录以访问此页面。'
    login_manager.login_message_category = 'warning'
    login_manager.refresh_view = 'auth.refresh'
    login_manager.needs_refresh_message = '请重新登录以继续。'
    login_manager.needs_refresh_message_category = 'warning'
    
    # 用户加载回调
    @login_manager.user_loader
    def load_user(user_id):
        from app.models.user import User
        return User.query.get(int(user_id))

def register_blueprints(app):
    """注册所有蓝图"""
    app.register_blueprint(main_bp)
    app.register_blueprint(auth_bp, url_prefix='/auth')
    app.register_blueprint(forum_bp, url_prefix='/forum')
    app.register_blueprint(chat_bp, url_prefix='/chat')
    app.register_blueprint(api_bp, url_prefix='/api')
    app.register_blueprint(admin_bp, url_prefix='/admin')

def register_error_handlers(app):
    """注册错误处理器"""
    
    @app.errorhandler(404)
    def not_found_error(error):
        return {
            'error': '资源未找到',
            'message': '请求的资源不存在',
            'code': 404
        }, 404
    
    @app.errorhandler(500)
    def internal_error(error):
        db.session.rollback()
        return {
            'error': '服务器内部错误',
            'message': '服务器遇到意外错误',
            'code': 500
        }, 500
    
    @app.errorhandler(403)
    def forbidden_error(error):
        return {
            'error': '访问被拒绝',
            'message': '您没有权限访问此资源',
            'code': 403
        }, 403

def register_context_processors(app):
    """注册上下文处理器"""
    
    @app.context_processor
    def inject_globals():
        """注入全局变量到模板"""
        from app.models.user import User
        from app.models.forum import Category
        
        current_user = None
        categories = []
        
        try:
            # 获取当前用户（如果已登录）
            from flask_login import current_user
            # 获取分类列表
            categories = Category.query.filter_by(is_active=True).all()
        except Exception:
            pass
            
        return dict(
            current_user=current_user,
            categories=categories,
            app_name="SteHub",
            app_version="2.0.0"
        )

def register_commands(app):
    """注册自定义命令行命令"""
    
    @app.cli.command("init-db")
    def init_db_command():
        """初始化数据库"""
        try:
            db.create_all()
            print("✅ 数据库初始化成功！")
            
            # 创建默认分类
            from app.models.forum import Category
            default_categories = [
                {"name": "学习交流", "description": "作业讨论、课程答疑", "color": "#3498db"},
                {"name": "资源共享", "description": "学习资料、工具推荐", "color": "#2ecc71"},
                {"name": "兴趣社区", "description": "编程、游戏、艺术等", "color": "#e74c3c"},
                {"name": "生活闲聊", "description": "日常话题、校园生活", "color": "#f39c12"}
            ]
            
            for cat_data in default_categories:
                category = Category.query.filter_by(name=cat_data["name"]).first()
                if not category:
                    category = Category(
                        name=cat_data["name"],
                        description=cat_data["description"],
                        color=cat_data["color"]
                    )
                    db.session.add(category)
            
            db.session.commit()
            print("✅ 默认分类创建成功！")
            
        except Exception as e:
            print(f"❌ 数据库初始化失败: {e}")
            db.session.rollback()

    @app.cli.command("create-admin")
    def create_admin_command():
        """创建管理员账户"""
        from app.models.user import User
        import getpass
        
        username = input("请输入管理员用户名: ")
        email = input("请输入管理员邮箱: ")
        password = getpass.getpass("请输入密码: ")
        confirm_password = getpass.getpass("请确认密码: ")
        
        if password != confirm_password:
            print("❌ 密码不匹配！")
            return
        
        try:
            admin = User(
                username=username,
                email=email,
                role='admin'
            )
            admin.set_password(password)
            db.session.add(admin)
            db.session.commit()
            print("✅ 管理员账户创建成功！")
        except Exception as e:
            print(f"❌ 创建管理员失败: {e}")
            db.session.rollback()

    @app.cli.command("export-local-data")
    def export_local_data_command():
        """导出本地数据"""
        import json
        from datetime import datetime
        
        try:
            data = {
                'export_time': datetime.utcnow().isoformat(),
                'users': [],
                'posts': [],
                'categories': []
            }
            
            # 导出用户数据（不包含密码）
            from app.models.user import User
            users = User.query.all()
            for user in users:
                data['users'].append({
                    'id': user.id,
                    'username': user.username,
                    'email': user.email,
                    'role': user.role,
                    'created_at': user.created_at.isoformat() if user.created_at else None
                })
            
            # 导出帖子数据
            from app.models.forum import Post
            posts = Post.query.all()
            for post in posts:
                data['posts'].append({
                    'id': post.id,
                    'title': post.title,
                    'content': post.content,
                    'author_id': post.author_id,
                    'category_id': post.category_id,
                    'created_at': post.created_at.isoformat() if post.created_at else None
                })
            
            # 导出分类数据
            from app.models.forum import Category
            categories = Category.query.all()
            for category in categories:
                data['categories'].append({
                    'id': category.id,
                    'name': category.name,
                    'description': category.description,
                    'color': category.color
                })
            
            # 保存到文件
            filename = f'stehub_export_{datetime.utcnow().strftime("%Y%m%d_%H%M%S")}.json'
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
            
            print(f"✅ 数据导出成功: {filename}")
            
        except Exception as e:
            print(f"❌ 数据导出失败: {e}")

def configure_logging(app):
    """配置日志"""
    if not app.debug:
        # 在生产环境中配置日志
        import logging
        from logging.handlers import RotatingFileHandler
        
        # 创建日志目录
        log_dir = 'logs'
        os.makedirs(log_dir, exist_ok=True)
        
        # 文件处理器
        file_handler = RotatingFileHandler(
            f'{log_dir}/stehub.log',
            maxBytes=1024 * 1024,  # 1MB
            backupCount=10
        )
        file_handler.setFormatter(logging.Formatter(
            '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
        ))
        file_handler.setLevel(logging.INFO)
        
        app.logger.addHandler(file_handler)
        app.logger.setLevel(logging.INFO)
        app.logger.info('SteHub 启动成功')

# 创建应用实例（用于开发）
app = create_app()

if __name__ == '__main__':
    socketio.run(app, debug=True)